home *** CD-ROM | disk | FTP | other *** search
- #include "pun.h"
- #include "xhdi.h"
-
- #include <string.h>
-
- #ifdef MFS_XFS
- #include "minixfs.h"
- #include "global.h"
- #define XRWABS RWABS
- #define DWARN(mes,drive) ALERT("Drive %c: " mes,drive)
- #else
- #define DWARN(mes,drive) fprintf(stderr,"Drive %c: " mes "\n",drive)
- #define ALERT(x) fprintf(stderr,x "\n")
- #define NEED_SUPER
- #define RWABS Rwabs
- #define Kmalloc malloc
- #define Kfree free
- #define GETBPB Getbpb
- #include <osbind.h>
- #include <alloc.h>
- #include <stdio.h>
- #include "hdio.h"
-
- #define XRWABS(a,b,c,d,e,f) \
- trap_13_wwlwwwl((short)(0x04),(short)(a),(long)(b),(short)(c),(short)(d)\
- ,(short)(e),(long)(f) )
-
- #define trap_13_wwlwwwl(n, a, b, c, d, e, f) \
- ({ \
- register long retvalue __asm__("d0"); \
- volatile short _a = (volatile short)(a); \
- volatile long _b = (volatile long) (b); \
- volatile short _c = (volatile short)(c); \
- volatile short _d = (volatile short)(d); \
- volatile short _e = (volatile short)(e); \
- volatile long _f = (volatile long) (f); \
- \
- __asm__ volatile \
- ("\
- movl %5,sp@-; \
- movw %4,sp@-; \
- movw %3,sp@-; \
- movw %2,sp@-; \
- movl %1,sp@-; \
- movw %0,sp@- " \
- : /* outputs */ \
- : "r"(_a), "r"(_b), "r"(_c), "r"(_d), "r"(_e), "r"(_f) /* inputs */ \
- ); \
- \
- __asm__ volatile \
- ("\
- movw %1,sp@-; \
- trap #13; \
- addw #18,sp " \
- : "=r"(retvalue) /* outputs */ \
- : "g"(n) /* inputs */ \
- : "d0", "d1", "d2", "a0", "a1", "a2" /* clobbered regs */ \
- ); \
- retvalue; \
- })
-
- #endif
-
- /* List of error codes for get_hddinf */
-
- char *hdd_err[] = {
- "OK",
- "Bad BPB on floppy drive", /* 1 */
- "Need drive A-P for PUN_INFO", /* 2 */
- "Invalid or no PUN_INFO structure", /* 3 */
- "Invalid drive", /* 4 */
- "Physical mode disabled for ICD software", /* 5 */
- "Physical lrecno error", /* 6 */
- "XHInqDev2 failed (old XHDI version?) and bad BPB", /* 7 */
- "XHInqDev failed", /* 8 */
- "Unrecognised partition id", /* 9 */
- "XHInqTarget failed", /* 10 */
- "Unsupported physical sector size", /* 11 */
- "Invalid partition start (zero BPB?)" /* 12 */
- "ICD software too old to fix", /* 13 */
- /* These are from set_lrecno */
- "Memory allocation failure", /* 14 */
- "Unable to access last block" /* 15 */
-
- };
-
-
- /*
- * Hard disk info. This is a general purpose routine to handle minixfs' needs
- * for hard disks. If this function returns non-zero then the partition
- * cannot be accessed. XHDI and pun_info are used to get partition info.
- * The structure 'hdinf' is filled in as approproiate.
- *
- * If this looks awful then that's because it *is*.
- */
-
- static char rno_xhdi,try_xhdi;
- static char try_lrecno,rno_lrecno;
- static char try_plrecno,rno_plrecno;
-
- char is_icd =-1 ;
- unsigned char *cache_icd;
-
- int get_hddinf(drive,hdinf,flag)
- int drive;
- struct hdinfo *hdinf;
- char flag;
- {
- long ret;
- #ifdef NEED_SUPER
- long tstack;
- tstack=Super(0l);
- if(!((*(long *)0x4c2) & (1l<<drive))) return 4;
- #endif
- ret = _get_hddinf(drive,hdinf,flag);
- #ifdef NEED_SUPER
- Super(tstack);
- #endif
- return ret;
- }
-
- int _get_hddinf(drive,hdinf,flag)
- int drive;
- struct hdinfo *hdinf;
- char flag;
- {
- _BPB *bpb;
-
- hdinf->major=drive; /* May get overwritten later */
-
- hdinf->drive=drive;
-
- init_icd();
-
- bpb=GETBPB(drive);
- if( flag ) bpb=0;
-
-
- /* Step 1: if bpb OK and sector size 512 bytes or 1K we may get away
- * with normal Rwabs.
- */
-
- if( !bpb || (bpb->recsiz!=512 && bpb->recsiz!=1024) )
- {
- long tsecsiz;
- char mpid[4];
-
- /* OK can't use normal Rwabs: try XHDI or pun_info */
-
- /* Bypass this rubbish for floppies */
- if(drive < 2 ) return 1;
-
- /* Try and get info from pun_inf structure */
- if( no_xhdi() )
- {
- struct pun_info *pinf;
- if(drive >= MAXUNITS) return 2;
- if(!(*(long *)0x516)) return 3;
- pinf=PUN_PTR;
- if(!pinf || (PUN_VALID & pinf->pun[drive]) ) return 4;
- hdinf->scsiz = 1;
-
- if(is_icd)
- #ifdef NO_ICD_PHYS
- return 5;
- #else
- {
- if(is_icd==2) return 13;
- hdinf->start = pinf->partition_start[drive+4];
- }
- #endif
- else hdinf->start = pinf->partition_start[drive];
-
- if(!hdinf->start) return 12;
-
- hdinf->size = 0;
- hdinf->minor = pinf->pun[drive];
- if(is_icd) hdinf->major=drive;
- else hdinf->major = (hdinf->minor & PUN_DEV) +2;
- hdinf->rwmode = RW_PHYS;
- /* We want to access at least first few sectors */
- if(hdinf->start > 0xfff0)
- {
- if(no_plrecno(hdinf->major)) return 6;
- else hdinf->rwmode |= RW_LRECNO;
- }
- return 0;
- }
-
- hdinf->rwmode = RW_XHDI | RW_LRECNO;
-
- /* Hmmmm Getbpb failed or bad secsize: see what XHDI can do */
-
- if( XHInqDev2(drive,&hdinf->major,&hdinf->minor,&hdinf->start,
- 0,&hdinf->size,mpid) )
- {
- if(!bpb && !flag ) return 7;
- if( XHInqDev(drive,&hdinf->major,&hdinf->minor,
- &hdinf->start,0) ) return 8;
- hdinf->size=0;
- }
- else if(!bpb && strcmp(mpid,"RAW") && strcmp(mpid,"MIX")
- && strcmp(mpid,"BGM") && strcmp(mpid,"GEM") ) return 9;
-
- /* Get physical sector size */
- if( XHInqTarget(hdinf->major,hdinf->minor,&tsecsiz,0,0) )
- return 10;
-
- if(tsecsiz==512) hdinf->scsiz=1;
- else
- {
- if(tsecsiz==1024) hdinf->scsiz=0;
- else return 11;
- }
- return 0;
- }
- if(bpb->recsiz==512) hdinf->scsiz=1;
- else hdinf->scsiz=0;
- hdinf->size=0;
- hdinf->rwmode = RW_NORMAL;
- return 0;
- }
-
- /* Special kludge for icd software. This software accesses far too many sectors
- * when physical mode I/O is attempted on sectors bigger than 0xffff with the
- * cache on. What we do
- * is to:
- * 1. Test for ICD software.
- * 2. Set a pointer to the 'cache flag'.
- * Return values:
- * 0 Non ICD software or PUN_INFO problem.
- * 1 Probably non ICD host adaptor used with ICD software.
- * 2 ICD software doesn't have a 'cache flag' (probably too old).
- * 3 Probably kludgable (OK).
- * Only '2' is fatal.
- */
-
-
- int init_icd()
- {
- char *icd_magic;
- if(is_icd!=-1) return is_icd;
- if(!*((long *)0x516)) return is_icd=0;
- icd_magic=((char *)PUN_PTR)-6;
- if(strncmp(icd_magic,"ICDB",4)) return is_icd=0;
- else
- {
- char *icdh_magic;
- if( icd_magic[5] < 0x50 ) return is_icd=2;
- icdh_magic=*((char ** )(icd_magic-4));
- if(strncmp(icdh_magic,"ICDH",4)) return is_icd=1;
- if( icdh_magic[4] < 0x50 ) return is_icd=2;
- cache_icd = (unsigned char *)(icdh_magic+6);
- return is_icd=3;
- }
- }
-
- /* This function is called after get_hddinf and is used to finalise the
- * accessibility of a partition. The 'size' parameter is the size of the
- * partition in K; this info will typically come from the super block of
- * a filesystem.
- * Return values:
- * 0 OK
- * 1 Malloc failure.
- * 2 Can't access last block.
- * 3 Physical lrecno error.
- */
-
- int set_lrecno(hdinf,size)
- struct hdinfo *hdinf;
- long size;
- {
- long tsize;
- tsize=size;
- if(hdinf->scsiz) tsize <<=1;
- if( ( (hdinf->rwmode & RW_MODE) == RW_XHDI) && hdinf->size
- && (hdinf->size < tsize) )
- {
- DWARN("Filesystem size bigger than partition size!",
- hdinf->drive);
- }
- else hdinf->size = tsize;
-
- hdinf->rwmode |= RW_CHECK;
-
- if(hdinf->rwmode & RW_LRECNO) return 0;
-
- switch(hdinf->rwmode & RW_MODE)
- {
- case RW_NORMAL:
- if(tsize < 0xffff)
- {
- char *tmp_buf;
- tmp_buf=Kmalloc(1024);
- if(!tmp_buf) return 14;
- /* Try to read last block */
- if(!block_rwabs(2,tmp_buf,1,size-1,hdinf))
- {
- Kfree(tmp_buf);
- return 0;
- }
- Kfree(tmp_buf);
- #ifndef BYPASS_LOGICAL
- return 15;
- #endif
- }
-
- if( tsize < 0xffff || no_lrecno(hdinf->major) )
- {
- /* Bad lrecno or access error, try physical mode access */
- int drive,err;
- drive = hdinf->major;
- if( (err=get_hddinf(drive,hdinf,1)) ) return err;
- else return (set_lrecno(hdinf,size));
- }
- else hdinf->rwmode |= RW_LRECNO;
- return 0;
-
- case RW_PHYS:
- if(tsize+hdinf->start >= 0xfffe)
- {
- if(no_plrecno(hdinf->major)) return 1;
- hdinf->size = tsize;
- hdinf->rwmode |= RW_LRECNO;
- }
- return 0;
- }
-
- return 1; /* This can't happen */
- }
-
- /* Test for 'lrecno' parameter on drive 'drive': mode' is RWABS mode to use
- * (2=logical,10=physical).
- * Return values:
- * 0 OK
- * 1 Read error.
- * 2 No lrecno recognised.
- * 3 Error reading large sector number (possibly OK if partition too small).
- * 4 Wraparound bug present.
- * 5 Allocation error.
- */
-
- int test_lrecno(drive,mode)
- int drive;
- int mode;
- {
- char *block_buf1,*block_buf2;
- int size;
- _BPB *bpb;
- bpb=Getbpb(drive);
- if( (mode & 8) || !bpb ) size=1024;
- else size=bpb->recsiz;
-
- block_buf1=Kmalloc(size<<1);
- block_buf2=block_buf1+size;
- bzero(block_buf1,size<<1);
-
- if(!block_buf1) return 5;
-
- /* read in boot sector */
- if(RWABS(mode,block_buf1,1,0,drive))
- {
- Kfree(block_buf1);
- return 1;
- }
-
- /* read it in with lrecno */
- if( XRWABS(mode,block_buf2,1,-1,drive,0l) )
- {
- Kfree(block_buf1);
- return 2;
- }
-
- /* Compare the two */
- if(bcmp(block_buf1,block_buf2,size))
- {
- Kfree(block_buf1);
- return 2;
- }
-
- /* read in next sector with lrecno */
- if(XRWABS(mode,block_buf2,1,-1,drive,1l))
- {
- Kfree(block_buf1);
- return 1;
- }
-
- /* compare the two */
- if(!bcmp(block_buf1,block_buf2,size))
- {
- Kfree(block_buf1);
- return 2;
- }
-
- /* Check for lrecno bug, this causes the upper word of a long sector
- * number to be ignored. Read in sector 0 and 0x10000, if the bug is
- * present then these will be identical.
- */
- bzero(block_buf2,size);
-
- if(XRWABS(mode,block_buf2,1,-1,drive,0x10000l))
- {
- Kfree(block_buf1);
- return 3;
- }
- else if(!bcmp(block_buf1,block_buf2,size))
- {
- Kfree(block_buf1);
- return 4;
- }
-
- Kfree(block_buf1);
- return 0;
-
- }
-
- int no_lrecno(drv)
- int drv;
- {
- if( !try_lrecno )
- {
- rno_lrecno = test_lrecno(drv,2) ;
- try_lrecno = 1;
- }
- return rno_lrecno;
- }
-
- int no_plrecno(drv)
- int drv;
- {
- #ifdef NO_ICD_PHYS
- if(is_icd) return 1;
- #endif
-
- if( !try_plrecno )
- {
- unsigned char cache_tmp=0;
- try_plrecno = 1;
- if(cache_icd)
- {
- cache_tmp=*cache_icd;
- *cache_icd=0;
- }
- rno_plrecno = test_lrecno(drv,10) ;
- if(cache_icd) *cache_icd=cache_tmp;
- }
- return rno_plrecno;
- }
-
- int no_xhdi()
- {
- if( !try_xhdi )
- {
- if( !XHGetVersion() ) rno_xhdi=1;
- try_xhdi=1;
- }
- return rno_xhdi;
- }
-
- /*
- * This is (finally!) the I/O function hdinf uses. It reads/writes in 1K chunks
- * and calls the relevant functions according to the hdinf structure.
- */
-
- long block_rwabs(rw,buf,num,recno,hdinf)
- int rw;
- void *buf;
- unsigned num;
- long recno;
- struct hdinfo *hdinf;
- {
- unsigned char cache_tmp=0;
- long ret;
-
- if( hdinf->scsiz )
- {
- recno <<=1;
- num <<=1;
- }
-
- if( (hdinf->rwmode & RW_CHECK) && (recno+num > hdinf->size) )
- {
- DWARN("Attempted access outside partition",hdinf->drive);
- return -1;
- }
-
- switch(hdinf->rwmode & (RW_MODE|RW_LRECNO))
- {
- case RW_NORMAL:
- return RWABS(rw,buf,num,(unsigned)recno,hdinf->major);
-
- case RW_NORMAL | RW_LRECNO:
- return XRWABS(rw,buf,num,-1,hdinf->major,recno);
-
- case RW_PHYS:
- if(cache_icd)
- {
- cache_tmp=*cache_icd;
- *cache_icd=0;
- }
- ret = RWABS(rw | 8,buf,num,(unsigned)(recno+hdinf->start),
- hdinf->major);
- if(cache_icd) *cache_icd=cache_tmp;
- return ret;
-
- case RW_PHYS | RW_LRECNO:
- if(cache_icd)
- {
- cache_tmp=*cache_icd;
- *cache_icd=0;
- }
- ret = XRWABS(rw | 8,buf,num,-1,hdinf->major,
- recno+hdinf->start);
- if(cache_icd) *cache_icd=cache_tmp;
- return ret;
-
- case RW_XHDI | RW_LRECNO:
- return XHReadWrite(hdinf->major,hdinf->minor,rw,
- recno+hdinf->start,num,buf);
- }
- return 1; /* This can't happen ! */
- }
-
- #ifndef SUPER_CALL
-
- /* Determine partition size from drive info. Check Rwabs errors ... it should
- * give an error for an attempt to read past the end of a partition. From then
- * on use a log search to find partition size.
- * If this seems awkward you are right ... certain disk software doesn't enter
- * the correct size in the boot sector (to correct a TOS bug).
- */
-
- char *size_err[] =
- {
- "OK",
- "Getbpb failed",
- "Allocation error",
- "Driver software incompatible"
- };
-
- int get_size(drive,size)
- int drive;
- long *size;
- {
- char *buf;
- _BPB *bpb;
- unsigned secnum,bitnum;
- if(! (bpb=GETBPB(drive)) ) return 1; /* Bad bpb */
- if(! (buf=Kmalloc(bpb->recsiz)) ) return 2; /* alloc error */
-
- if(!RWABS(2,buf,1,0xfffe,drive))
- {
- Kfree(buf);
- return 3; /* Software doesn't return errors */
- }
-
- bitnum=0x8000;
- secnum=0;
-
- do
- {
- secnum |= bitnum;
- if( RWABS(2,buf,1,secnum,drive) ) secnum &=~bitnum;
- bitnum >>=1 ;
- } while(bitnum);
-
- secnum++;
-
- *size=(((long)secnum) * bpb->recsiz)>>10;
- Kfree(buf);
- return 0;
-
- }
-
- #endif
-
-
-
-